// Larbin
// Sebastien Ailleret
// 15-11-99 -> 04-12-01

#include <iostream>
#include <errno.h>
#include <sys/types.h>

#include "options.h"

#include "global.h"
#include "types.h"
#include "utils/Fifo.h"
#include "utils/debug.h"
#include "interf/output.h"
#include "utils/url.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

static struct sockaddr_in stataddr;
static time_t lastFetchTime;
void initFetch () {
  bzero(&stataddr,sizeof(stataddr));
  stataddr.sin_family = AF_INET;
  lastFetchTime=time(NULL);
}
/*
 * establish a connection
 */
static char getFds (Connexion *conn, struct in_addr *addr, uint port) {
  memcpy (&stataddr.sin_addr,
          addr,
          sizeof (struct in_addr));
  stataddr.sin_port = htons(port);
  int fd = socket(AF_INET, SOCK_STREAM, 0);
  if (fd < 0)
    return emptyC;
  else
    global::verifMax(fd);
  conn->socket = fd;
  for (;;) {
    fcntl(fd, F_SETFL, O_NONBLOCK);
    struct sockaddr_in *theaddr;
    if (global::proxyAddr != NULL)
      theaddr = global::proxyAddr;
    else
      theaddr = &stataddr;
    if (connect(fd, (struct sockaddr*) theaddr,
                sizeof (struct sockaddr_in)) == 0) {
      // success
      return writeC;
    } else if (errno == EINPROGRESS) {
      // would block
      return connectingC;
    } else {
      // error
      (void) close(fd);
      return emptyC;
    }
  }
}
/*
 * get a url from ram or disk
 * if no url,return null
 */
static url* getUrl()
{
	url *u;
	if((u=global::URLsPriority->tryGet()) != NULL)
		return u;
	else
	{
		u=global::URLsDisk->tryGet();
		return u;
	}
}
/*
 * open a socket connection and prepare http request
 * each request needs a connection if use http/1.0,but now for some web sites ,http 1.1 is supported,so there can be set to long connection
 */
static int prepareFetch(url * u)
{

	if(global::now-lastFetchTime<global::waitDuration) //too early
		return 0;
	lastFetchTime=time(NULL);
	Connexion *conn = global::freeConns->get();
	char res = getFds(conn, &(global::addr), u->getPort());
	if (res != emptyC) {
	    conn->timeout = timeoutPage;
	    conn->request.addString("GET ");
	    if (global::proxyAddr != NULL) {
	       char *tmp = u->getUrl();
	       conn->request.addString(tmp);
	    } else {
	       conn->request.addString(u->getFile());
	    }
	    conn->request.addString(" HTTP/1.0\r\nHost: ");
	    conn->request.addString(u->getHost());
	#ifdef COOKIES
	    if (u->cookie != NULL) {
	      conn->request.addString("\r\nCookie: ");
	      conn->request.addString(u->cookie);
	    }
	#endif // COOKIES
	    conn->request.addString(global::headers);
	    conn->parser = new html (u, conn);
	    conn->pos = 0;
	    conn->err = success;
	    conn->state = res;
	    return 1;
	} else {
	    // Unable to connect
	    fetchFail(u, noConnection);
	    delete u;
	    global::freeConns->put(conn);
	    addFailedConn();
	    return 0;
    }
}
/*
 * prepare for fetch
 */
void fetchOpen () {
  int cont = 1;
  while (cont && global::freeConns->isNonEmpty()) {
    url *u = getUrl();
    if (u == NULL) {
      cont = 0;
    } else {
      cont = prepareFetch(u);
    }
  }
}



